#if !defined(FISH_H_)
#define FISH_H_

/* For struct Timer routines. */
#include <sys/time.h>
#include <time.h>

#if defined(HAVE_ISNAN)||defined(HAVE_FMAX)
#include <math.h>
#endif

/* Structure to represent a fish state
 * floats are 4 bytes, so this structure
 * is 24 bytes = 6*4... not good! A multiple
 * of 16 is needed for DMA transfers (add pad)
 */
typedef struct {
  float x;
  float y;
  float vx;
  float vy;
  float ax;
  float ay;
  int pad[2]; // sum to 32bytes
} fish_t;

#define FISH_MASS ((float) 1.0)

#define LEFT_WALL ((float) (1.0))
#define RIGHT_WALL ((float) (2.0))
#define WALL_SEP (RIGHT_WALL - LEFT_WALL)

/* --- Options ----------------------------------------------------- */

extern int n_fish; /* Number of fish */

extern float max_norm_change; /* Maximum allowable norm change / step */
extern float max_dt; /* Max allowed time step */
extern float min_dt; /* Min allowed time step */
extern float end_time; /* Ending time for the simulation */
extern int max_steps; /* Maximum number of steps */

extern float min_r; /* Cutoff distance for attraction computation */
extern float min_r2; /* min_r squared */
extern float G; /* Gravitational constant */

extern float output_interval; /* Min time between outputs */
extern char *output_filename; /* File to receive results */
extern char *input_filename;

extern int uniformp; /* Flag if initial configuration is unif. distributed. */
extern int outvelp;

#define STRINGARG_MAXLEN 1024
typedef enum { NULLARG, INTARG, DOUBLEARG, STRINGARG } arg_type_t;

struct arginfo {
  char c;
  arg_type_t type;
  void* val;
  const char* desc;
};

extern struct arginfo* ext_args;

/* --- Useful functions -------------------------------------------- */

/* The C99 fmax and fmin functions aren't defined on many platforms. */
#ifdef _AIX 
#define inline __inline
#endif

static inline float
f_max (float a, float b)
{
  if (a > b) return a;
  if (b > a) return b;
#if defined(HAVE_ISNAN)
  if (isnan(a)) return b;
#else
  if (a != a) return b;
#endif
  return a;
}

static inline float
f_min (float a, float b)
{
  if (a < b) return a;
  if (b < a) return b;
#if defined(HAVE_ISNAN)
  if (isnan(a)) return b;
#else
  if (a != a) return b;
#endif
  return a;
}

/* --- fish-lib ---------------------------------------------------- */

/* Process the command line options */
void get_options(int, char **);

float scale_coord(float);
float unscale_coord(float);

/* A simple wrapper around the clock() timer */
struct Timer {
  struct timeval clock_holder;
  struct timeval duration;
};

void initialize_timer (struct Timer* t);
void start_timer (struct Timer* t);
void stop_timer (struct Timer* t);
float timer_duration(const struct Timer t);

#endif /* FISH_H_ */
